package com.xuecheng.media.service.job;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileService;
import com.xuecheng.media.service.MediaProcessService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.minio.GetObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author luhao
 * @ClassName VideoTaskJob.java
 * @Description 视频处理文件
 * @createTime 2023/9/5
 */
@Slf4j
@Component
public class VideoTaskJob {
    @Value("${minio.bucket.files:mediafiles}")
    private String bucketFiles;

    @Value("${minio.bucket.videofiles:video}")
    private String bucketVideo;
    @Autowired
    private MediaProcessService mediaProcessService;

    @Autowired
    private MediaFileService mediaFileService;

    @Value("${videoprocess.ffmpegpath}")
    private String ffmpeg_path;

    @XxlJob("videoJobHandler")
    @Transactional
    public void videoJobHandler() throws InterruptedException {
        XxlJobHelper.log("视频任务处理开始");
        // 获取分片索引
        int shardIndex = XxlJobHelper.getShardIndex();
        // 获取分片总数
        int shardTotal = XxlJobHelper.getShardTotal();
        // 获取待处理的媒资信息
        int processors = Runtime.getRuntime().availableProcessors();
        List<MediaProcess> listByShardIndex = mediaProcessService.getListByShardIndex(shardIndex, shardTotal, processors);
        int size = listByShardIndex.size();
        log.info("待处理的任务数为：{}", size);
        if (size < 0) {
            log.info("待处理的视频任务为0,处理任务结束");
            return;
        }
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(size);
        // 计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        listByShardIndex.forEach(mediaProcess -> {
            executorService.execute(() -> {
                // 多线程抢占任务
                Long id = mediaProcess.getId();
                boolean isSuccess = mediaProcessService.startTaskById(id);
                if (!isSuccess) {
                    return;
                }
                // 获取抢占任务的媒资信息
                String bucket = mediaProcess.getBucket();
                String filePath = mediaProcess.getFilePath();
                String fileId = mediaProcess.getFileId();
                String filename = mediaProcess.getFilename();
                GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucket).object(filePath).build();
                File downLoadFile = mediaFileService.downLoadFile(fileId, filename, getObjectArgs);
                if (ObjectUtil.isNull(downLoadFile)) {
                    log.error("下载文件:{},存储桶：{},文件路径：{}为空", mediaProcess.getFilename(), bucket, filePath);
                    mediaProcessService.saveProcessFinishStatus(id, "3", fileId, null, "下载minio文件为空", null);
                    return;
                }
                String temp = "temp";
                String suffix = ".mp4";
                String tempName = temp + suffix;
                File tempFile;
                try {
                    tempFile = File.createTempFile(temp, suffix);
                    if (tempFile == null) {
                        log.error("创建零时文件:{},为空", tempName);
                        mediaProcessService.saveProcessFinishStatus(id, "3", fileId, null, "创建mp4零时文件为空", null);
                        return;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error("创建零时文件:{},失败", tempName);
                    mediaProcessService.saveProcessFinishStatus(id, "3", fileId, null, "创建mp4零时文件异常", null);
                    return;
                }

                // 创建mp4转换工具
                Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpeg_path,
                        downLoadFile.getAbsolutePath(), tempName, tempFile.getAbsolutePath());
                String generated = mp4VideoUtil.generateMp4();
                if (!generated.equals("success")) {
                    log.error("文件:{},转换mp4文件失败", tempName);
                    mediaProcessService.saveProcessFinishStatus(id, "3", fileId, null, "转换mp4文件失败", null);
                    return;
                }
                // 上传文件名称
                String uploadFileName = fileId + suffix;
                // 获取修改文件后minio上传路径
                String uploadPath = StrUtil.replace(filePath, ".avi", suffix);
                // 上传url
                String uploadUrl = StrUtil.SLASH + bucket + StrUtil.SLASH + uploadPath;

                boolean uploadMinio = mediaFileService.uploadMinio(tempFile.getAbsolutePath(), uploadPath, "video/mp4", bucketVideo);
                if (uploadMinio) {
                    log.info("上传文件：{},到minio成功", uploadFileName);
                    mediaProcessService.saveProcessFinishStatus(id, "2", fileId, uploadUrl, null, StrUtil.replace(filename, ".avi", suffix));
                } else {
                    log.error("上传文件：{},到minio失败", uploadFileName);
                    mediaProcessService.saveProcessFinishStatus(id, "3", fileId, null, "上传到minio失败", null);
                }
                mediaFileService.deleteUploadFile(filePath, bucketVideo);
                // 计数减一
                countDownLatch.countDown();
            });
        });
        // 主线程阻塞等待最大时间
        countDownLatch.await(30L, TimeUnit.MINUTES);
        XxlJobHelper.log("视频任务处理结束");
    }
}
